using System;
using System.Collections.Generic;
using System.Text;
using RapidHDL.Fabric;

namespace RapidHDL.Fabric
{
    public class MicroCoreBlock : Block
    {

        Dictionary<string, ControlState> dicFabricControlStates;
        Dictionary<string, StatusOutput> dicFabricStatusBits;

        MicroCoreComponent oCore;
        MicroCoreTable oTable;
        int iWidth;

        public MicroCoreBlock(string psName, MicroCoreTable poTable, Dictionary<string,ControlState> pdicControlStates, Dictionary<string,StatusOutput> pdicFabricStatusBits)
            : base(psName,"CORE")
        {
            oTable = poTable;
            
            if (oTable.ROM.Count == 0)
                oTable.CompileROM();

            iWidth = Conversion.MinBitWidth(oTable.ROM.Count - 1);
            dicFabricControlStates = pdicControlStates;
            dicFabricStatusBits = pdicFabricStatusBits;
            this.CreateInput("IR", iWidth);
        }

        internal override void GenerateStructure()
        {
            oCore = new MicroCoreComponent(ParentComponent, "core_" + Name, oTable, Clock, Reset);
            Inputs["IR"].LinkNodeVector(oCore.I_InstructionReg);

            foreach (string sControl in oCore.O_ControlLines.Keys)
            {
                string sControlState = sControl.Substring(0, sControl.Length - 2);
                if (!dicFabricControlStates.ContainsKey(sControlState))
                    throw new Exception("Fabric doesn't have a control line named " + sControlState);
                ControlState oControlState = dicFabricControlStates[sControlState];
                oControlState.Input.NodeVector.Join(oCore.O_ControlLines[sControl]);
            }
            if (!dicFabricControlStates.ContainsKey("PC_INC"))
            {
                throw new Exception("There is no control state {PC_INC} to increment the program counter.");
            }
            ControlState oControlState_PC_INC = dicFabricControlStates["PC_INC"];
            oControlState_PC_INC.Input.NodeVector.Join(oCore.O_PC_NEXT);

            foreach (string sStatus in oCore.I_StatusBits.Keys)
            {
                string sStatusBit = sStatus.Substring(0, sStatus.Length - 2);
                if (!dicFabricStatusBits.ContainsKey(sStatusBit))
                    throw new Exception("Fabric doesn't have a status bit named " + sStatusBit);
                dicFabricStatusBits[sStatusBit].NodeVector.Join(oCore.I_StatusBits[sStatus]);
            }
        }

        public override void AddSignalViews()
        {
            oCore.AddSignalViews();
        }

        public void SignalDisplay(HardwareScript poScript, int piClockTime)
        {
            oCore.SignalDisplay(poScript, piClockTime);
        }

        public MicroCoreTable GetTable()
        {
            return oTable;
        }

    }
}
